package com.languages

import com.excel.SaveExcel
import com.excel.SheetHeadComment
import com.languages.entity.CommentAtt
import com.languages.entity.KeyValue
import com.languages.entity.StyleValue
import com.utils.YamlUtil
import org.apache.logging.log4j.kotlin.logger
import org.apache.poi.hssf.usermodel.HSSFCellStyle
import org.apache.poi.hssf.usermodel.HSSFRow
import org.apache.poi.hssf.usermodel.HSSFSheet
import org.apache.poi.ss.usermodel.FillPatternType
import org.apache.poi.ss.usermodel.IndexedColors
import org.apache.poi.ss.usermodel.VerticalAlignment
import org.dom4j.Element
import org.dom4j.Node
import org.dom4j.io.SAXReader
import org.dom4j.tree.DefaultComment
import kotlin.io.encoding.Base64
import kotlin.io.encoding.ExperimentalEncodingApi
import kotlin.io.path.extension
import kotlin.io.path.inputStream
import kotlin.io.path.isDirectory
import kotlin.io.path.nameWithoutExtension

class ToExcel {
    /**
     * 要被处理的语言
     */
    private var headComments = mutableListOf<SheetHeadComment>()
    private val list1 = mutableListOf<Any>()
    private val mapData: MutableMap<String, List<KeyValue<CommentAtt>>> = HashMap()

    // 原生语言名字
    private val languageOld = mutableListOf<String?>()

    /**
     * 整理后的语言名字
     */
    private lateinit var names: MutableList<String>

    fun start() {
        headComments.clear()

        val languages = YamlUtil.getLanguages()!!

        headComments.addAll(languages.headLanguage)

        val path = languages.languagesPath!!
        logger.info("读取xml路径=$path")
        logger.info("输出目录=${languages.outPath}")
        logger.info("输出XLS路径=${languages.xlsPath}")
        val list = path.walk().filter {
            !it.isDirectory() && it.extension.lowercase().endsWith("xml")
        }.toMutableList()

        logger.info("读取到xml文件数量=" + list.size)
        val reader = SAXReader()
        for (file in list) { // 将所有的路径都拿出来
            logger.info("解析xml文件=$file")
            val document = reader.read(file.inputStream())
            val root = document.rootElement
            // 读取数据
            val it: Iterator<*> = root.nodeIterator()
            var commentText = "" // 注释
            val keyValues = mutableListOf<KeyValue<CommentAtt>>()
            var keyValue: KeyValue<CommentAtt>
            var index: Int
            var commentAtt: CommentAtt
            var attrList: MutableList<String?>
            while (it.hasNext()) {
                val node = it.next() as Node
                if (node.nodeType == Node.COMMENT_NODE) { // 如果是注释 表示新的一个组件
                    val comment = node as DefaultComment
//                    System.out.println("a = " + comment.getText());
                    commentText = comment.text.trim { it <= ' ' }
                } else if (node.nodeType == Node.ELEMENT_NODE) {
                    val element = node as Element
//                    System.out.println("b = " + element.attributeValue("name") + " | " + element.getText());
                    keyValue = KeyValue(element.text) // 将文本做为key存入
                    attrList = mutableListOf()
                    for (i in 0 until element.attributeCount()) {
                        attrList.add(element.attribute(i).name + "=" + element.attribute(i).value)
                    }
                    commentAtt = CommentAtt(commentText, attrList)
                    if ((keyValues.indexOf(keyValue).also { index = it }) != -1) { // 存在这个值了
                        keyValue = keyValues[index]
                        keyValue.value?.add(commentAtt)
                    } else {
                        // 不存在
                        val list2 = mutableListOf<CommentAtt>()
                        list2.add(commentAtt)
                        keyValue.value = list2
                        keyValues.add(keyValue)
                    }
                    keyValue.attach.add(element.asXML())
                }
            }
            val name = file.nameWithoutExtension
            mapData[name] = keyValues
        }

        list1.clear()
        list1.add(SheetHeadComment("temp", "转换xml映射使用的数据，不可修改"))
        list1.add("描述")
        list1.add(headComments[0])
        for (i in 1 until headComments.size) {
            list1.add(headComments[i].content!!)
        }

        val saveExcel = SaveExcel()
        //生成单元格样式
        val headStyle = saveExcel.wb.createCellStyle()
        headStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND)
        headStyle.fillForegroundColor = IndexedColors.LIGHT_ORANGE.index // 颜色
        headStyle.setVerticalAlignment(VerticalAlignment.TOP)

        val valueStyle = saveExcel.wb.createCellStyle()
        valueStyle.wrapText = true
        valueStyle.setVerticalAlignment(VerticalAlignment.TOP)

        // 获取所有语言的简写
        val keys = mapData.keys
        // 重新放入一个 list 数组 整理后的语言名字

        names = mutableListOf()
        for (key in keys) {
            names.add(key)
        }
        // 排序
        names.sort()

        logger.info("排序后的名称=" + names.joinToString(","))

        val defaultLanguage = headComments[0].languages
        for (key in names) {
            logger.info("检测文件=$key,$defaultLanguage startsWith对比")
            if (key.startsWith(defaultLanguage)) {
//                System.out.println("**********************************  " + key);
                val sheet = saveExcel.addSheet(key)
                saveExcel.addHead(sheet, *list1.toTypedArray())
                for (i in list1.indices) {
                    if (i < 2) {
                        sheet.setColumnWidth(i, 200 * 35)
                    } else {
                        sheet.setColumnWidth(i, 400 * 35)
                    }
                }
                createExe(key, saveExcel, sheet, headStyle, valueStyle)
                languageOld.add(key)
            }
        }
        saveExcel.save( languages.outPath!!.resolve(path.nameWithoutExtension + ".xls").pathString)
    }


    /**
     * 创建格子
     * @param keyName   语言名字
     * @param saveExcel 保存对象
     * @param sheet     sheet
     * @param style     颜色
     * @param style2    文本换行
     */
    private fun createExe(
        keyName: String,
        saveExcel: SaveExcel,
        sheet: HSSFSheet,
        style: HSSFCellStyle,
        style2: HSSFCellStyle
    ) {
        val keyValues = mapData[keyName]!!
        logger.info("语言=" + keyName + ", 查到的数据len=" + keyValues.size)
        var hssfRow: HSSFRow?
        var keyValue: KeyValue<CommentAtt>
        var id: String
        var stringMap: Map<String?, String?>
        var tempName: String
        var sheetHeadComment: SheetHeadComment
        for (i in keyValues.indices) {
            keyValue = keyValues[i]
            // 创建一行
            hssfRow = saveExcel.addCellValue(sheet)
            id = getName(keyValue)
            // 在指定的一行上创建一列并添加值
            val cell = saveExcel.addCellValue(hssfRow, StyleValue(id, style)) // id
            sheetHeadComment = SheetHeadComment(null, keyValue.attach.joinToString("\n"))
            saveExcel.addCellComment(cell, sheetHeadComment)

            saveExcel.addCellValue(hssfRow, "") // 描述环境
            saveExcel.addCellValue(hssfRow, StyleValue(keyValue.keys, style2)) // 原始文字
            for (j in 1 until headComments.size) {
                // 获取这个配置集合
                stringMap = this.getLanguageData(keyValue.value, keyName)
                tempName = headComments[j].languages
                val value = keyName.split("_")
                logger.info("新语言=" + tempName + ", 默认语言=" + keyName + ", len=" + stringMap.size)
                if (value.size == 2) {
                    tempName += "_" + keyName.substringAfter("_")
                }
                logger.info("new typeName=$tempName")
                saveExcel.addCellValue(hssfRow, StyleValue(stringMap[tempName], style2)) // 描述环境
            }
        }
    }

    /**
     * 根据id 获取语言
     * @param typeNames typeNames
     * @param keyName   语言名字
     * @return
     */
    private fun getLanguageData(typeNames: List<CommentAtt>?, keyName: String): Map<String?, String?> {
        val maps: MutableMap<String?, String?> = HashMap()
        val value = keyName.split("_")
        if (value.size == 2) { // 表示不是主语言 是语言其他配置文本
            for (i in names.indices) {
                if (names[i].endsWith(value[1])) { // 如果符合配置符号
                    val list = mapData[names[i]]!!
                    for (j in list.indices) {
                        for (k in typeNames!!.indices) {
                            val list20 = list[j].value
                            for (l in list20!!.indices) {
                                if (list20[l].name == typeNames[k].name) {
                                    maps[names[i]] = list[j].keys
                                }
                            }
                        }
//                        if (this.getName(list.get(j)).equals(id)) {
//                            maps.put(this.names.get(i), list.get(j).getKeys());
//                        }
                    }
                }
            }
        } else {
            for (i in names.indices) {
                if (!names[i].contains("_")) { // 如果符合配置符号
                    val list = mapData[names[i]]!!
                    for (j in list.indices) {
                        for (k in typeNames!!.indices) {
                            val list20 = list[j].value
                            for (l in list20!!.indices) {
                                if (list20[l].name == typeNames[k].name) {
                                    maps[names[i]] = list[j].keys
                                }
                            }
                        }
//                        if (this.getName(list.get(j)).equals(id)) {
//                            maps.put(this.names.get(i), list.get(j).getKeys());
//                        }
                    }
                }
            }
        }
        return maps
    }

    @OptIn(ExperimentalEncodingApi::class)
    fun getName(keyValue: KeyValue<CommentAtt>): String {
        var name = ""
        for (i in keyValue.value!!.indices) {
            if (i > 0) {
                name += "|" + keyValue.value!![i].data
            } else {
                name = keyValue.value!![i].data
            }
        }
        return Base64.encode(name.toByteArray())
    }

}
